package sql.constraints;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

public class TableConstraint implements Serializable {
    private static final long serialVersionUID = 1L;

    private String name;
    private ConstraintType type;
    private List<String> columns; // 约束涉及的列

    // 为 FOREIGN KEY 准备的字段
    private String referencedTable;
    private List<String> referencedColumns;

    // 为 CHECK 准备的字段
    private String checkCondition;

    // 为 DEFAULT 准备的字段
    private String defaultValue;

    // 私有构造函数，供 fromMap 使用
    private TableConstraint() {}

    /**
     * 用于 NOT_NULL, UNIQUE, PRIMARY_KEY 的构造函数。
     */
    public TableConstraint(String name, ConstraintType type, List<String> columns) {
        if (type == ConstraintType.FOREIGN_KEY || type == ConstraintType.CHECK) {
            throw new IllegalArgumentException("请为 FOREIGN_KEY 或 CHECK 约束使用特定的构造函数或工厂方法。");
        }
        this.name = Objects.requireNonNull(name, "约束名称不能为空");
        this.type = Objects.requireNonNull(type, "约束类型不能为空");
        this.columns = Objects.requireNonNull(columns, "约束列不能为空");

        if (columns.isEmpty() && 
            (type == ConstraintType.PRIMARY_KEY || type == ConstraintType.UNIQUE || type == ConstraintType.NOT_NULL)) {
             throw new IllegalArgumentException("PRIMARY_KEY, UNIQUE, 或 NOT_NULL 约束的列列表不能为空。");
        }
        if (type == ConstraintType.NOT_NULL && columns.size() != 1) {
            throw new IllegalArgumentException("NOT_NULL 约束必须且只能应用于一个列。");
        }
    }

    /**
     * 创建 FOREIGN_KEY 约束的工厂方法。
     */
    public static TableConstraint createForeignKeyConstraint(String name, List<String> columns, String referencedTable, List<String> referencedColumns) {
        TableConstraint constraint = new TableConstraint();
        constraint.name = Objects.requireNonNull(name, "约束名称不能为空");
        constraint.type = ConstraintType.FOREIGN_KEY;
        constraint.columns = Objects.requireNonNull(columns, "约束列不能为空");
        constraint.referencedTable = Objects.requireNonNull(referencedTable, "FOREIGN_KEY 约束的引用表不能为空");
        constraint.referencedColumns = Objects.requireNonNull(referencedColumns, "FOREIGN_KEY 约束的引用列不能为空");
        if (columns.isEmpty() || referencedColumns.isEmpty() || columns.size() != referencedColumns.size()) {
            throw new IllegalArgumentException("FOREIGN_KEY 约束的列和引用列必须非空且数量相同。");
        }
        return constraint;
    }

    /**
     * 创建 CHECK 约束的工厂方法。
     */
    public static TableConstraint createCheckConstraint(String name, String checkCondition, List<String> involvedColumns) {
        TableConstraint constraint = new TableConstraint();
        constraint.name = Objects.requireNonNull(name, "约束名称不能为空");
        constraint.type = ConstraintType.CHECK;
        constraint.checkCondition = Objects.requireNonNull(checkCondition, "CHECK 约束的检查条件不能为空");
        // 参与 CHECK 约束的列，可能从 checkCondition 解析得到，或显式传递
        constraint.columns = involvedColumns != null ? new ArrayList<>(involvedColumns) : new ArrayList<>();
        return constraint;
    }

    /**
     * 创建 DEFAULT 约束的工厂方法。
     */
    public static TableConstraint createDefaultConstraint(String name, String column, String defaultValue) {
        TableConstraint constraint = new TableConstraint();
        constraint.name = Objects.requireNonNull(name, "约束名称不能为空");
        constraint.type = ConstraintType.DEFAULT;
        constraint.columns = new ArrayList<>();
        constraint.columns.add(column);
        constraint.defaultValue = defaultValue;
        return constraint;
    }

    // Getters
    public String getName() { return name; }
    public ConstraintType getType() { return type; }
    public List<String> getColumns() { return columns; }
    public String getReferencedTable() { return referencedTable; }
    public List<String> getReferencedColumns() { return referencedColumns; }
    public String getCheckCondition() { return checkCondition; }
    public String getDefaultValue() { return defaultValue; }

    /**
     * 从 Map 对象创建 TableConstraint 实例。
     */
    @SuppressWarnings("unchecked")
    public static TableConstraint fromMap(Map<String, Object> map) {
        TableConstraint constraint = new TableConstraint();
        constraint.name = (String) map.get("name");
        String typeStr = (String) map.get("type");
        if (typeStr == null) {
            throw new IllegalArgumentException("从 Map 创建约束时，类型不能为空。");
        }
        try {
            constraint.type = ConstraintType.valueOf(typeStr);
        } catch (IllegalArgumentException e) {
            throw new IllegalArgumentException("从 Map 创建约束时，无效的约束类型: " + typeStr, e);
        }
        
        constraint.columns = (List<String>) map.get("columns");
        if (constraint.columns == null) { // 确保 columns 列表总是被初始化
            constraint.columns = new ArrayList<>();
        }

        if (constraint.type == ConstraintType.FOREIGN_KEY) {
            constraint.referencedTable = (String) map.get("referencedTable");
            constraint.referencedColumns = (List<String>) map.get("referencedColumns");
        } else if (constraint.type == ConstraintType.CHECK) {
            constraint.checkCondition = (String) map.get("checkCondition");
        } else if (constraint.type == ConstraintType.DEFAULT) {
            constraint.defaultValue = (String) map.get("defaultValue");
        }
        return constraint;
    }

    /**
     * 将 TableConstraint 实例转换为 Map 对象，以便存储。
     */
    public Map<String, Object> toMap() {
        Map<String, Object> map = new HashMap<>();
        map.put("name", this.name);
        map.put("type", this.type.name()); // 将枚举存储为字符串
        map.put("columns", this.columns);

        if (this.type == ConstraintType.FOREIGN_KEY) {
            map.put("referencedTable", this.referencedTable);
            map.put("referencedColumns", this.referencedColumns);
        } else if (this.type == ConstraintType.CHECK) {
            map.put("checkCondition", this.checkCondition);
        } else if (this.type == ConstraintType.DEFAULT) {
            map.put("defaultValue", this.defaultValue);
        }
        return map;
    }

    @Override
    public String toString() {
        return "TableConstraint{" +
                "name='" + name + '\'' +
                ", type=" + type +
                ", columns=" + columns +
                (referencedTable != null ? ", referencedTable='" + referencedTable + '\'' : "") +
                (referencedColumns != null ? ", referencedColumns=" + referencedColumns : "") +
                (checkCondition != null ? ", checkCondition='" + checkCondition + '\'' : "") +
                (defaultValue != null ? ", defaultValue='" + defaultValue + '\'' : "") +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        TableConstraint that = (TableConstraint) o;
        return Objects.equals(name, that.name) &&
               type == that.type &&
               Objects.equals(columns, that.columns) &&
               Objects.equals(referencedTable, that.referencedTable) &&
               Objects.equals(referencedColumns, that.referencedColumns) &&
               Objects.equals(checkCondition, that.checkCondition) &&
               Objects.equals(defaultValue, that.defaultValue);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, type, columns, referencedTable, referencedColumns, checkCondition, defaultValue);
    }
} 